﻿#region using

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Media;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using CoreAudioApi;
using JariZ;
using Microsoft.Win32;

#endregion

namespace JCore
{
    internal class AdBlockCore
    {
        private readonly Version vs = Environment.OSVersion.Version;
        private bool isMuted;
        public bool started = false;
        private SpotifyAPI API;

        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);

        [DllImport("User32.dll", SetLastError = true)]
        public static extern Boolean keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

        public void StartAdBlock()
        {
            API = new SpotifyAPI(SpotifyAPI.GetOAuth(), "jipjan.spotilocal.com");
            started = true;

            #region bullshit, maybe usefull later on

            /*            
            
            //Create and/or check mutex existence in a race-free way
            bool created;
            if (File.Exists(Environment.ExpandEnvironmentVariables(@"%appdata%\Spotify\prefs")))
            {
                using (
                    StreamReader reader =
                        new StreamReader(Environment.ExpandEnvironmentVariables(@"%appdata%\Spotify\prefs")))
                {
                    string temp = reader.ReadToEnd();
                    temp = temp.Substring((temp.IndexOf("autologin.username=", StringComparison.Ordinal) + 20),
                                          temp.Count() - (temp.IndexOf("autologin.username=") + 22));
                    // lblUsername.Text = "Logged in as: " + temp;
                }
            }
            else
            {
                // lblUsername.Text = "Can't find username, sorry! =(";
            }

            //check if registry contains key, if not create one else read it to a int.
            // Opening the registry key
            RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\.:Jip-Jan:.", true);
            // If the RegistrySubKey doesn't exist -> (null)
            if (rk != null)
            {
                try
                {
                    totalAdsBlocked = Convert.ToInt32(rk.GetValue("TotalBlocked", "0"));
                    // lblAdsBlocked.Text = "Total ads blocked: " + totalAdsBlocked;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
            else
            {
                rk = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\.:Jip-Jan:.");
                rk.SetValue("TotalBlocked", "0");
            }

            // silent update
            if (rk != null)
            {
                try
                {
                    Boolean.TryParse(rk.GetValue("SilentUpdate", "true").ToString(), out silentUpdate);
                    // silentUpdateToolStripMenuItem.Checked = silentUpdate;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
            else
            {
                rk = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\.:Jip-Jan:.");
                rk.SetValue("SilentUpdate", "true");
            }


            if (IsProcessOpen("spotify") == false)
            {
                Process.Start(Environment.ExpandEnvironmentVariables(@"%Appdata%\Spotify\spotify.exe"));
            }
            if (File.Exists(Application.StartupPath + @"\Public.dat"))
            {
                addPublicToList();
            }
            else
            {
                if (
                    MessageBox.Show("There is no database detected, do you want to download the latest database?",
                                    "No database found!", MessageBoxButtons.YesNo, MessageBoxIcon.Question) ==
                    DialogResult.Yes)
                {
                    try
                    {
                        downloadDatabase();
                        // addPublicToList();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString());
                        //    MessageBox.Show("Something went wrong downloading =(");                            
                    }
                }
            }

            if (File.Exists(Application.StartupPath + @"\Private.dat"))
            {
                // addPrivateToList();
            }

            if (File.Exists(Application.StartupPath + @"\BlackList.dat"))
            {
                addBlockListToList();
            }
            else
            {
                if (
                    MessageBox.Show("There is no blocklist detected, do you want to download the latest blocklist?",
                                    "No blocklist found!", MessageBoxButtons.YesNo, MessageBoxIcon.Question) ==
                    DialogResult.Yes)
                {
                    try
                    {
                        downloadBlacklist();
                        addBlockListToList();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString());
                        //    MessageBox.Show("Something went wrong downloading =(");                            
                    }
                }
            }
            if (File.Exists(Application.StartupPath + @"\Updater.exe") == false)
            {
                // WriteResourceToFile("Updater.exe");
            }
            if (File.Exists(Application.StartupPath + @"\CoreAudioApi.dll") == false)
            {
                WriteResourceToFile("CoreAudioApi.dll");
            }
            // option...
            checkForUpdates(false);

            
            */

            #endregion
        }



        public bool IsProcessOpen(string name)
        {
            foreach (Process clsProcess in Process.GetProcesses())
            {
                if (clsProcess.ProcessName.Contains(name))
                {
                    return true;
                }
            }
            //otherwise we return a false
            return false;
        }


        private void SetIsMuted(bool isMuted)
        {
            this.isMuted = isMuted;
        }

        private static void Mute()
        {
            // WERKT
            Process[] spotify = Process.GetProcessesByName("spotify");
            // Mute
            // 0x28 = down arrow key
            // 0x11 = ctrl
            // keydown event = 0
            // key up = 0x0002 = 0x2
            for (int i = 0; i < 11; i++)
            {
                keybd_event(0x11, 0x1D, 0, 0);
                SendMessage(spotify[0].MainWindowHandle, 0x0100, 0x28, null);
            }
            Thread.Sleep(50);
            keybd_event(0x11, 0x1D, 0x2, 0);
            SendMessage(spotify[0].MainWindowHandle, 0x0100, 0x20, null);
        }

        private static void newMute(bool muted)
        {
            MMDeviceEnumerator DevEnum = new MMDeviceEnumerator();
            MMDevice device = DevEnum.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
            try
            {
                for (int i = 0; i < device.AudioSessionManager.Sessions.Count; i++)
                {
                    AudioSessionControl session = device.AudioSessionManager.Sessions[i];
                    Process p = Process.GetProcessById((int) session.ProcessID);
                    if (p.ProcessName == "spotify")
                    {
                        SimpleAudioVolume vol = session.SimpleAudioVolume;
                        vol.Mute = !vol.Mute;
                        if (muted == false)
                        {
                            SendMessage(p.MainWindowHandle, 0x0100, 0x20, null);
                            /*
                            // Press play media button
                            keybd_event(0xB3, 0x1D, 0, 0);
                            // release button
                            keybd_event(0xB3, 0x1D, 0x2, 0);
                            */
                        }
                        else
                        {
                            vol.Mute = !vol.Mute;
                            vol.Mute = !vol.Mute;
                        }
                        break;
                    }
                }
            }
            catch
            {
            }
        }

        private static void unMute()
        {
            Process[] spotify = Process.GetProcessesByName("spotify");
            // max volume
            // 0x26 = up
            for (int i = 0; i < 11; i++)
            {
                keybd_event(0x11, 0x1D, 0, 0);
                SendMessage(spotify[0].MainWindowHandle, 0x0100, 0x26, null);
            }
            Thread.Sleep(50);
            keybd_event(0x11, 0x1D, 0x2, 0);
        }

        public void AdBlock()
        {
            if (started)
            {
                Process[] spotify = Process.GetProcessesByName("spotify");
                
                Responses.Status currentStatus = API.Status;

                // AdBlocking
                // check if spotify is running
                if (spotify.Length > 0 && currentStatus.track != null)
                {
                    if (isMuted == false && currentStatus.track.track_type == "ad")
                    {
                        if (vs.Major == 6)
                        {
                            newMute(false);
                        }
                        else
                        {
                            Mute();
                        }
                        SetIsMuted(true);
                        //lblAdsBlocked.Text = "Total ads blocked: " + (totalAdsBlocked + adsBlocked);
                        SystemSounds.Beep.Play();
                        //Text = "Spotify Unlimited (Beta) ~ Ads blocked this session: " + adsBlocked;
                    }
                    if (isMuted && currentStatus.track.track_type != "ad")
                    {
                        if (vs.Major == 6)
                        {
                            newMute(true);
                        }
                        else
                        {
                            unMute();
                        }
                        SetIsMuted(false);
                    }
                    
                }
            }
        }

        #region adblockingtests
        [DllImport("user32.dll")]
        public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
        [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
        public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(IntPtr hObject);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", EntryPoint = "FindWindowEx", CharSet = CharSet.Auto)]
        static extern IntPtr FindWindowEx(IntPtr hwndParent,
          IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll")]
        static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, RedrawWindowFlags flags);
        private enum RedrawWindowFlags : uint
        {
            /// <summary>
            /// Invalidates the rectangle or region that you specify in lprcUpdate or hrgnUpdate.
            /// You can set only one of these parameters to a non-NULL value. If both are NULL, RDW_INVALIDATE invalidates the entire window.
            /// </summary>
            Invalidate = 0x1,

            /// <summary>Causes the OS to post a WM_PAINT message to the window regardless of whether a portion of the window is invalid.</summary>
            InternalPaint = 0x2,

            /// <summary>
            /// Causes the window to receive a WM_ERASEBKGND message when the window is repainted.
            /// Specify this value in combination with the RDW_INVALIDATE value; otherwise, RDW_ERASE has no effect.
            /// </summary>
            Erase = 0x4,

            /// <summary>
            /// Validates the rectangle or region that you specify in lprcUpdate or hrgnUpdate.
            /// You can set only one of these parameters to a non-NULL value. If both are NULL, RDW_VALIDATE validates the entire window.
            /// This value does not affect internal WM_PAINT messages.
            /// </summary>
            Validate = 0x8,

            NoInternalPaint = 0x10,

            /// <summary>Suppresses any pending WM_ERASEBKGND messages.</summary>
            NoErase = 0x20,

            /// <summary>Excludes child windows, if any, from the repainting operation.</summary>
            NoChildren = 0x40,

            /// <summary>Includes child windows, if any, in the repainting operation.</summary>
            AllChildren = 0x80,

            /// <summary>Causes the affected windows, which you specify by setting the RDW_ALLCHILDREN and RDW_NOCHILDREN values, to receive WM_ERASEBKGND and WM_PAINT messages before the RedrawWindow returns, if necessary.</summary>
            UpdateNow = 0x100,

            /// <summary>
            /// Causes the affected windows, which you specify by setting the RDW_ALLCHILDREN and RDW_NOCHILDREN values, to receive WM_ERASEBKGND messages before RedrawWindow returns, if necessary.
            /// The affected windows receive WM_PAINT messages at the ordinary time.
            /// </summary>
            EraseNow = 0x200,

            Frame = 0x400,

            NoFrame = 0x800
        }
        private const short SWP_NOZORDER = 0x4;
        private const short SWP_HIDEWINDOW = 0x80;
        private const short SWP_NOACTIVATE = 0x10;
        private const short SWP_NOREDRAW = 0x8;
        private const short SWP_NOSIZE = 0x1;
        private const short SWP_NOMOVE = 0x2;
        private const short SWP_SHOWWINDOW = 0x0040;

        public bool SetWindowSizeAndLocation(IntPtr window, IntPtr window2, IntPtr window3)
        {
            // Process[] spotify = Process.GetProcessesByName("spotify");
            // Tweede WebDing
            SetWindowPos(window, 0, 0, 0, 10, 10, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
            SetWindowPos(window2, 0, 0, 0, 10, 10, SWP_NOZORDER | SWP_NOACTIVATE);
            SetWindowPos(window3, 0, 0, 0, 10, 10, SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE);
            // RedrawWindow(window, IntPtr.Zero, IntPtr.Zero, RedrawWindowFlags.Erase);
            return true;
        }

        





        [DllImport("user32.dll")]
        static extern bool GetMessage(ref Message lpMsg, IntPtr hWnd, uint wMsgFilterMin,
           uint wMsgFilterMax);

        private Message msg = new Message();

        public void MessageTest()
        {
            while (GetMessage(ref msg, (IntPtr)0x001305A2, 0, 0))
            {
                Console.WriteLine(msg.Msg);
            }
        }

        static List<IntPtr> GetAllChildrenWindowHandles(IntPtr hParent,
  int maxCount)
        {
            List<IntPtr> result = new List<IntPtr>();
            int ct = 0;
            IntPtr prevChild = IntPtr.Zero;
            IntPtr currChild = IntPtr.Zero;
            while (true && ct < maxCount)
            {
                currChild = FindWindowEx(hParent, prevChild, null, null);
                if (currChild == IntPtr.Zero) break;
                result.Add(currChild);
                prevChild = currChild;
                ++ct;
            }
            return result;
        }
        #endregion
    }
}
        
    
